﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Reflection;
using Go;

namespace GoRpc
{
    static public class Rpc
    {
        enum DataType
        {
            Keep,
            NoKeep,
            Close,
            Request,
            RequestCancel,
            Reply,
            Bin,
            BinCancel,
        }

        [Serializable]
        struct Request
        {
            public bool reply;
            public string name;
            public RecvName[] sends;
        }

        [Serializable]
        struct Reply
        {
            public ReplyState state;
            public string message;
        }

        [Serializable]
        public enum ReplyState
        {
            Fail,
            Success,
            Stopped,
            NotFound,
            Overtime,
            Exception,
            LocalCancel,
            RemoteCancel,
            ArgsTypeError,
            ArgsCountError,
            ResultTypeError,
            LocalSerializeError,
            RemoteSerializeError,
            LocalDeserializeError,
            RemoteDeserializeError,
        }

        class CastArgsException : Exception
        {
        }

        abstract public class ParamTuple
        {
            [Serializable]
            internal struct SerializePack
            {
                public string name;
                public object value;
            }

            [Serializable]
            internal struct Serialize
            {
                public string name;
                public SerializePack[] array;
            }

            [AttributeUsage(AttributeTargets.Field)]
            public class Name : Attribute
            {
                internal string rename;

                public Name(string rename)
                {
                    this.rename = rename;
                }
            }

            [AttributeUsage(AttributeTargets.Class)]
            public class Match : Attribute
            {
                internal string rename;

                public Match(string rename)
                {
                    this.rename = rename;
                }
            }

            class TypeInfo
            {
                public string name;
                public bool[] isParam;
                public Type[] fieldTypes;
                public string[] paramNames;
                public Func<object, object>[] getValue;
                public Action<object, object>[] setValue;
            }

            protected ParamTuple() { }

            protected ParamTuple(object objects)
            {
                if (objects is Serialize)
                {
                    Objects = (Serialize)objects;
                }
                else
                {
                    throw new CastArgsException();
                }
            }
#if DEBUG
            static bool CheckTempType(Type[] types)
            {
                for (int i = 0; i < types.Length; i++)
                {
                    if (types[i].IsSubclassOf(typeof(ParamTuple)))
                    {
                        return false;
                    }
                    if (!CheckTempType(types[i].GetGenericArguments()))
                    {
                        return false;
                    }
                }
                return true;
            }

            static public void AssertName()
            {
                Dictionary<string, void_type> nameDict = new Dictionary<string, void_type>();
                Assembly assembly = Assembly.GetCallingAssembly();
                Type[] allTypes = assembly.GetTypes();
                foreach (Type type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    bool isMatch = Attribute.IsDefined(type, typeof(Match));
                    if (!type.IsSubclassOf(typeof(ParamTuple)) && !isMatch)
                    {
                        continue;
                    }
                    TypeInfo typeInfo = GetTypeInfo(type);
                    if (!isMatch)
                    {
                        continue;
                    }
                    Debug.Assert(null != typeInfo.name && 0 != typeInfo.name.Length, $"Rpc.ParamTuple 定义名称不能为空\r\n\r\n{assembly.FullName}");
                    if (nameDict.ContainsKey(typeInfo.name))
                    {
                        Debug.Assert(false, $"Rpc.ParamTuple 定义名称 {typeInfo.name} 重复\r\n\r\n{assembly.FullName}");
                    }
                    else
                    {
                        nameDict.Add(typeInfo.name, default);
                    }
                }
                foreach (var type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    if (!Attribute.IsDefined(type, typeof(Match)))
                    {
                        continue;
                    }
                    nameDict.Clear();
                    TypeInfo typeInfo = GetTypeInfo(type);
                    if (!type.IsSubclassOf(typeof(ParamTuple)))
                    {
                        Debug.Assert(false, $"{typeInfo.name} 没有继承自 Rpc.ParamTuple\r\n\r\n{assembly.FullName}");
                    }
                    foreach (string name in typeInfo.paramNames)
                    {
                        Debug.Assert(null != name && 0 != name.Length, $"{typeInfo.name} 字段名称不能为空\r\n\r\n{assembly.FullName}");
                        if (nameDict.ContainsKey(name))
                        {
                            Debug.Assert(false, $"{typeInfo.name} 字段名称 {name} 重复\r\n\r\n{assembly.FullName}");
                        }
                        else
                        {
                            nameDict.Add(name, default);
                        }
                    }
                }
                foreach (Type type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    if (!type.IsSubclassOf(typeof(ParamTuple)))
                    {
                        continue;
                    }
                    TypeInfo typeInfo = GetTypeInfo(type);
                    if (null == typeInfo.name)
                    {
                        FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
                        for (int i = 0; i < typeInfo.fieldTypes.Length; i++)
                        {
                            Debug.Assert(CheckTempType(fields[i].FieldType.GetGenericArguments()), $"{type.Name} 字段 {fields[i].Name} 的模板不能使用ParamTuple派生类型\r\n\r\n{assembly.FullName}");
                        }
                    }
                    else
                    {
                        for (int i = 0; i < typeInfo.fieldTypes.Length; i++)
                        {
                            Debug.Assert(CheckTempType(typeInfo.fieldTypes[i].GetGenericArguments()), $"{typeInfo.name} 字段 {typeInfo.paramNames[i]} 的模板不能使用ParamTuple派生类型\r\n\r\n{assembly.FullName}");
                        }
                    }
                }
            }
#else
            static public void AssertName()
            {
                Assembly assembly = Assembly.GetCallingAssembly();
                Type[] allTypes = assembly.GetTypes();
                foreach (Type type in allTypes)
                {
                    if (type.IsAbstract)
                    {
                        continue;
                    }
                    if (!type.IsSubclassOf(typeof(ParamTuple)))
                    {
                        continue;
                    }
                    GetTypeInfo(type);
                }
            }
#endif
            static internal bool IsParam(Type type, bool checkArray)
            {
                while (checkArray && type.IsArray)
                {
                    type = type.GetElementType();
                }
                do
                {
                    type = type.BaseType;
                    if (null == type)
                    {
                        return false;
                    }
                } while (type != typeof(ParamTuple));
                return true;
            }

            static object GetParams(Type type, object value)
            {
                if (null == value)
                {
                    return null;
                }
                if (!type.IsArray)
                {
                    return ((ParamTuple)value).Objects;
                }
                Type elementType = type.GetElementType();
                object[] values = (object[])value;
                object[] objects = new object[values.Length];
                for (int i = 0; i < values.Length; i++)
                {
                    objects[i] = GetParams(elementType, values[i]);
                }
                return objects;
            }

            static object SetParams(Type type, object oldObj, object value)
            {
                if (null == value)
                {
                    return null;
                }
                if (!type.IsArray)
                {
                    ParamTuple param = (ParamTuple)(oldObj ?? Activator.CreateInstance(type));
                    param.Objects = (Serialize)value;
                    return param;
                }
                Type elementType = type.GetElementType();
                object[] values = (object[])value;
                object[] objects;
                if (null == oldObj)
                {
                    objects = (object[])Activator.CreateInstance(type, values.Length);
                }
                else
                {
                    object[] oldObjs = (object[])oldObj;
                    if (oldObjs.Length == values.Length)
                    {
                        objects = oldObjs;
                    }
                    else
                    {
                        objects = (object[])Activator.CreateInstance(type, values.Length);
                        for (int i = 0; i < oldObjs.Length && i < objects.Length; i++)
                        {
                            objects[i] = oldObjs[i];
                        }
                    }
                }
                for (int i = 0; i < values.Length; i++)
                {
                    objects[i] = SetParams(elementType, objects[i], values[i]);
                }
                return objects;
            }

            static readonly ConcurrentDictionary<Type, TypeInfo> typeInfos = new ConcurrentDictionary<Type, TypeInfo>();
            static TypeInfo GetTypeInfo(Type type)
            {
                if (!typeInfos.TryGetValue(type, out TypeInfo typeInfo))
                {
                    FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
                    Match dict = (Match)Attribute.GetCustomAttribute(type, typeof(Match));
                    typeInfo = new TypeInfo();
                    typeInfo.name = dict?.rename;
                    typeInfo.isParam = new bool[fields.Length];
                    typeInfo.fieldTypes = new Type[fields.Length];
                    typeInfo.paramNames = new string[fields.Length];
                    typeInfo.getValue = new Func<object, object>[fields.Length];
                    typeInfo.setValue = new Action<object, object>[fields.Length];
                    for (int i = 0; i < fields.Length; i++)
                    {
                        typeInfo.paramNames[i] = ((Name)Attribute.GetCustomAttribute(fields[i], typeof(Name)))?.rename;
                        typeInfo.getValue[i] = CreateObjectGetter(fields[i]);
                        typeInfo.setValue[i] = CreateObjectSetter(fields[i], false);
                        typeInfo.isParam[i] = IsParam(fields[i].FieldType, true);
                        typeInfo.fieldTypes[i] = fields[i].FieldType;
                    }
                    typeInfos.TryAdd(type, typeInfo);
                }
                return typeInfo;
            }

            internal Serialize Objects
            {
                get
                {
                    TypeInfo typeInfo = GetTypeInfo(GetType());
                    SerializePack[] array = new SerializePack[typeInfo.getValue.Length];
                    for (int i = 0; i < typeInfo.getValue.Length; i++)
                    {
                        array[i].name = typeInfo.paramNames[i];
                        if (typeInfo.isParam[i])
                        {
                            array[i].value = GetParams(typeInfo.fieldTypes[i], typeInfo.getValue[i](this));
                        }
                        else
                        {
                            array[i].value = typeInfo.getValue[i](this);
                        }
                    }
                    return new Serialize { name = typeInfo.name, array = array };
                }
                set
                {
                    if (null == value.array)
                    {
                        throw new CastArgsException();
                    }
                    TypeInfo typeInfo = GetTypeInfo(GetType());
                    if (null == typeInfo.name)
                    {
                        if (typeInfo.setValue.Length != value.array.Length)
                        {
                            throw new CastArgsException();
                        }
                        for (int i = 0; i < typeInfo.setValue.Length; i++)
                        {
                            try
                            {
                                if (typeInfo.isParam[i])
                                {
                                    typeInfo.setValue[i](this, SetParams(typeInfo.fieldTypes[i], typeInfo.getValue[i](this), value.array[i].value));
                                }
                                else
                                {
                                    typeInfo.setValue[i](this, value.array[i].value);
                                }
                            }
                            catch (Exception)
                            {
                                throw new CastArgsException();
                            }
                        }
                    }
                    else if (typeInfo.name == value.name)
                    {
                        int lastOffset = 0;
                        for (int i = 0; i < typeInfo.setValue.Length; i++)
                        {
                            try
                            {
                                for (int j = 0; j < value.array.Length; j++)
                                {
                                    int k = lastOffset + j;
                                    if (k >= value.array.Length)
                                    {
                                        k -= value.array.Length;
                                    }
                                    if (typeInfo.paramNames[i] == value.array[k].name)
                                    {
                                        if (typeInfo.isParam[i])
                                        {
                                            typeInfo.setValue[i](this, SetParams(typeInfo.fieldTypes[i], typeInfo.getValue[i](this), value.array[k].value));
                                        }
                                        else
                                        {
                                            typeInfo.setValue[i](this, value.array[k].value);
                                        }
                                        lastOffset = k + 1;
                                        if (lastOffset >= value.array.Length)
                                        {
                                            lastOffset -= value.array.Length;
                                        }
                                        break;
                                    }
                                }
                            }
                            catch (Exception)
                            {
                                throw new CastArgsException();
                            }
                        }
                    }
                    else
                    {
                        throw new CastArgsException();
                    }
                }
            }
        }

        static Func<object, object[], object> CreateCall(MethodInfo methodInfo)
        {
            var paramTypes = methodInfo.GetParameters();
            var instancetObj = Expression.Parameter(typeof(object));
            var paramObjs = Expression.Parameter(typeof(object[]));
            var fixedObjs = new ParameterExpression[paramTypes.Length];
            var expressions = new LinkedList<Expression>();
            for (int i = 0; i < paramTypes.Length; i++)
            {
                var paramType = paramTypes[i].ParameterType;
                fixedObjs[i] = Expression.Variable(paramType);
                var idxParam = Expression.ArrayIndex(paramObjs, Expression.Constant(i));
                if (ParamTuple.IsParam(paramType, false))
                {
                    expressions.AddLast(Expression.Call(Expression.Assign(fixedObjs[i], Expression.New(paramType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null))),
                        paramType.GetMethod("set_Objects", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic),
                        Expression.Convert(idxParam, typeof(ParamTuple.Serialize))));
                }
                else
                {
                    expressions.AddLast(Expression.Assign(fixedObjs[i], Expression.Convert(idxParam, paramType)));
                }
            }
            if (0 != expressions.Count)
            {
                expressions.AddLast(Expression.Constant(null));
                var castBody = Expression.Block(expressions);
                var newExp = Expression.New(typeof(CastArgsException).GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null));
                var throwBody = Expression.Block(Expression.Throw(newExp), Expression.Constant(null));
                expressions.Clear();
                expressions.AddLast(Expression.TryCatch(castBody, Expression.Catch(typeof(InvalidCastException), throwBody)));
            }
            var callExp = methodInfo.IsStatic ? Expression.Call(methodInfo, fixedObjs) : Expression.Call(Expression.Convert(instancetObj, methodInfo.DeclaringType), methodInfo, fixedObjs);
            if (methodInfo.ReturnType == typeof(void))
            {
                expressions.AddLast(callExp);
                expressions.AddLast(Expression.Constant(null));
            }
            else
            {
                expressions.AddLast(Expression.Convert(callExp, typeof(object)));
            }
            var callBody = Expression.Block(fixedObjs, expressions);
            return Expression.Lambda<Func<object, object[], object>>(callBody, instancetObj, paramObjs).Compile();
        }

        static Func<object, object> CreateObjectGetter(FieldInfo fieldInfo)
        {
            Type objType = fieldInfo.DeclaringType;
            var paramObj = Expression.Parameter(typeof(object));
            var fixedObj = Expression.Variable(objType);
            var cvtExp = fieldInfo.IsStatic ? null : Expression.Assign(fixedObj, Expression.Convert(paramObj, objType));
            var interField = Expression.Field(cvtExp, fieldInfo);
            var cvtToObj = Expression.Convert(interField, typeof(object));
            var getFieldBody = Expression.Block(new ParameterExpression[] { fixedObj }, cvtToObj);
            return Expression.Lambda<Func<object, object>>(getFieldBody, paramObj).Compile();
        }

        static Action<object, object> CreateObjectSetter(FieldInfo fieldInfo, bool checkParam)
        {
            Type objType = fieldInfo.DeclaringType;
            Type fieldType = fieldInfo.FieldType;
            var paramObj = Expression.Parameter(typeof(object));
            var fixedObj = Expression.Variable(objType);
            var valueObj = Expression.Parameter(typeof(object));
            var cvtExp = fieldInfo.IsStatic ? null : Expression.Assign(fixedObj, Expression.Convert(paramObj, objType));
            var interField = Expression.Field(cvtExp, fieldInfo);
            Expression setField;
            if (checkParam && ParamTuple.IsParam(fieldType, false))
            {
                setField = Expression.Call(Expression.Assign(interField, Expression.New(fieldType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null))),
                    fieldType.GetMethod("set_Objects", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic),
                    Expression.Convert(valueObj, typeof(ParamTuple.Serialize)));
            }
            else
            {
                setField = Expression.Assign(interField, Expression.Convert(valueObj, fieldType));
            }
            var setFieldBody = Expression.Block(new ParameterExpression[] { fixedObj }, setField);
            return Expression.Lambda<Action<object, object>>(setFieldBody, paramObj, valueObj).Compile();
        }

        public class Methods
        {
            static public Delegate Cast(Action handler) => handler;
            static public Delegate Cast<T0>(Action<T0> handler) => handler;
            static public Delegate Cast<T0, T1>(Action<T0, T1> handler) => handler;
            static public Delegate Cast<T0, T1, T2>(Action<T0, T1, T2> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3>(Action<T0, T1, T2, T3> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4>(Action<T0, T1, T2, T3, T4> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5>(Action<T0, T1, T2, T3, T4, T5> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6>(Action<T0, T1, T2, T3, T4, T5, T6> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7>(Action<T0, T1, T2, T3, T4, T5, T6, T7> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF> handler) => handler;

            static public Delegate Cast<R>(Func<R> handler) => handler;
            static public Delegate Cast<T0, R>(Func<T0, R> handler) => handler;
            static public Delegate Cast<T0, T1, R>(Func<T0, T1, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, R>(Func<T0, T1, T2, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, R>(Func<T0, T1, T2, T3, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, R>(Func<T0, T1, T2, T3, T4, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, R>(Func<T0, T1, T2, T3, T4, T5, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, R>(Func<T0, T1, T2, T3, T4, T5, T6, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, R> handler) => handler;
            static public Delegate Cast<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TA, TB, TC, TD, TE, TF, R> handler) => handler;

            struct BindObjInfo
            {
                public bool isTask;
                public int argsCount;
                public Func<object, object[], object> method;
                public Func<object, object[], object> valueTask;
                public Func<object, object[], object> getResult;
            }

            [AttributeUsage(AttributeTargets.Method | AttributeTargets.Field)]
            public class AllowBind : Attribute
            {
                internal bool getter;
                internal bool setter;
                internal string rename;

                public AllowBind(bool getter = true, bool setter = true, string rename = null)
                {
                    this.getter = getter;
                    this.setter = setter;
                    this.rename = rename;
                }
            }

            [Serializable]
            public struct Name
            {
                internal string name;

                public Name(string name)
                {
                    this.name = name;
                }

                static public implicit operator string(Name rval)
                {
                    return rval.name;
                }
            }

            static long _nameid = DateTime.Now.Ticks;
            ConcurrentDictionary<string, tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand>> _methodsMap =
                new ConcurrentDictionary<string, tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand>>();

            static public Name GenName
            {
                get
                {
                    return new Name(Interlocked.Increment(ref _nameid).ToString());
                }
            }

            public void Bind(string name, Func<object[], Task> handler, shared_strand runStrand = null)
            {
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => handler(args), runStrand);
            }

            public void Bind(string name, Func<object[], ValueTask> handler, shared_strand runStrand = null)
            {
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => handler(args).AsTask() ?? generator.non_async(), runStrand);
            }

            public void Bind(string name, Func<object[], ValueTask<void_type>> handler, shared_strand runStrand = null)
            {
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => handler(args).AsTask() ?? generator.non_async(), runStrand);
            }

            private async Task bind_wait<R>(async_result_wrap<object, ReplyState> resWrap, Task<R> task)
            {
                resWrap.value1 = await task;
            }

            public void Bind<R>(string name, Func<object[], Task<R>> handler, shared_strand runStrand = null)
            {
                Add(name, delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                {
                    Task<R> task = handler(args);
                    if (!task.IsCompleted)
                    {
                        return bind_wait(resWrap, task);
                    }
                    resWrap.value1 = task.GetAwaiter().GetResult();
                    return generator.non_async();
                }, runStrand);
            }

            public void Bind<R>(string name, Func<object[], ValueTask<R>> handler, shared_strand runStrand = null)
            {
                Add(name, delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                {
                    ValueTask<R> task = handler(args);
                    if (!task.IsCompleted)
                    {
                        return bind_wait(resWrap, task.AsTask());
                    }
                    resWrap.value1 = task.GetAwaiter().GetResult();
                    return generator.non_async();
                }, runStrand);
            }

            public void Bind(string name, Action<object[]> handler, shared_strand runStrand = null)
            {
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => { handler(args); return generator.non_async(); }, runStrand);
            }

            public void Bind<R>(string name, Func<object[], R> handler, shared_strand runStrand = null)
            {
                Debug.Assert("Task`1" != typeof(R).Name && "Task" != typeof(R).Name && "ValueTask`1" != typeof(R).Name && "ValueTask" != typeof(R).Name, "Bind 不能绑定异步操作");
                Add(name, (async_result_wrap<object, ReplyState> resWrap, object[] args) => { resWrap.value1 = handler(args); return generator.non_async(); }, runStrand);
            }

            public void Bind(string name, Delegate handler, shared_strand runStrand = null, bool dynamicInvoke = false)
            {
                MethodInfo method = handler.GetType().GetMethod("Invoke");
                ParameterInfo[] argsInfo = method.GetParameters();
                BindObjInfo methodInfo = new BindObjInfo();
                methodInfo.argsCount = argsInfo.Length;
                if (dynamicInvoke)
                {
                    bool[] isParam = Array.ConvertAll(argsInfo, (ParameterInfo v) => ParamTuple.IsParam(v.ParameterType, false));
                    methodInfo.method = delegate (object obj, object[] args)
                    {
                        try
                        {
                            for (int i = 0; i < args.Length; i++)
                            {
                                if (isParam[i])
                                {
                                    ParamTuple paramTuple = (ParamTuple)Activator.CreateInstance(argsInfo[i].ParameterType);
                                    paramTuple.Objects = (ParamTuple.Serialize)args[i];
                                    args[i] = paramTuple;
                                }
                            }
                        }
                        catch (Exception)
                        {
                            throw new CastArgsException();
                        }
                        return method.Invoke(obj, args);
                    };
                }
                else
                {
                    methodInfo.method = CreateCall(method);
                }
                Type returnType = method.ReturnType;
                string returnTypeName = returnType.Name;
                if ("Task" == returnTypeName || "Task`1" == returnTypeName)
                {
                    methodInfo.isTask = true;
                    MethodInfo getResult = returnType.GetMethod("get_Result");
                    if (null != getResult)
                    {
                        methodInfo.getResult = dynamicInvoke ? (object task, object[] args) => getResult.Invoke(task, args) : CreateCall(getResult);
                    }
                }
                else if ("ValueTask" == returnTypeName || "ValueTask`1" == returnTypeName)
                {
                    MethodInfo asTask = returnType.GetMethod("AsTask");
                    MethodInfo getResult = returnType.GetMethod("GetResult");
                    methodInfo.valueTask = dynamicInvoke ? (object task, object[] args) => asTask.Invoke(task, args) : CreateCall(asTask);
                    methodInfo.getResult = dynamicInvoke ? (object task, object[] args) => getResult.Invoke(task, args) : CreateCall(getResult);
                }
                Add(name, async delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                {
                    if (methodInfo.argsCount != args.Length)
                    {
                        resWrap.value2 = ReplyState.ArgsCountError;
                        return;
                    }
                    try
                    {
                        if (methodInfo.isTask)
                        {
                            Task task = (Task)methodInfo.method(handler, args);
                            await task;
                            if (null != methodInfo.getResult)
                            {
                                resWrap.value1 = methodInfo.getResult(task, new object[0]);
                            }
                        }
                        else if (null != methodInfo.valueTask)
                        {
                            object result = methodInfo.method(handler, args);
                            Task task = (Task)methodInfo.valueTask(result, new object[0]);
                            if (null != task)
                            {
                                await task;
                            }
                            resWrap.value1 = methodInfo.getResult(result, new object[0]);
                        }
                        else
                        {
                            resWrap.value1 = await generator.send_task(() => methodInfo.method(handler, args));
                        }
                    }
                    catch (CastArgsException)
                    {
                        resWrap.value2 = ReplyState.ArgsTypeError;
                    }
                    catch (ArgumentException)
                    {
                        resWrap.value2 = ReplyState.ArgsTypeError;
                    }
                }, runStrand);
            }

            public string[] BindStatic(string name, Type type, bool checkBindAttr, shared_strand runStrand = null, bool dynamicInvoke = false)
            {
                return BindClass(name, type, null, checkBindAttr, runStrand, dynamicInvoke);
            }

            public string[] BindObj<T>(string name, T obj, bool checkBindAttr, shared_strand runStrand = null, bool dynamicInvoke = false)
            {
                return BindClass(name, typeof(T), obj, checkBindAttr, runStrand, dynamicInvoke);
            }

            private string[] BindClass(string name, Type type, object obj, bool checkBindAttr, shared_strand runStrand, bool dynamicInvoke)
            {
                MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
                var allBinds = new LinkedList<tuple<string, Func<async_result_wrap<object, ReplyState>, object[], Task>>>();
                var overrideMethod = new Dictionary<string, LinkedList<BindObjInfo>>();
                for (int i = 0; i < methods.Length; i++)
                {
                    MethodInfo method = methods[i];
                    if (null == obj && !method.IsStatic)
                    {
                        continue;
                    }
                    AllowBind allowBind = null;
                    if (checkBindAttr && null == (allowBind = (AllowBind)Attribute.GetCustomAttribute(method, typeof(AllowBind))))
                    {
                        continue;
                    }
                    BindObjInfo methodInfo = new BindObjInfo();
                    ParameterInfo[] argsInfo = method.GetParameters();
                    methodInfo.argsCount = argsInfo.Length;
                    if (dynamicInvoke)
                    {
                        bool[] isParam = Array.ConvertAll(argsInfo, (ParameterInfo v) => ParamTuple.IsParam(v.ParameterType, false));
                        methodInfo.method = delegate (object obj_, object[] args)
                        {
                            object[] args_ = null;
                            try
                            {
                                for (int j = 0; j < args.Length; j++)
                                {
                                    if (isParam[j])
                                    {
                                        if (null == args_)
                                        {
                                            args_ = new object[args.Length];
                                            args.CopyTo(args_, 0);
                                        }
                                        ParamTuple paramTuple = (ParamTuple)Activator.CreateInstance(argsInfo[j].ParameterType);
                                        paramTuple.Objects = (ParamTuple.Serialize)args_[j];
                                        args_[j] = paramTuple;
                                    }
                                }
                            }
                            catch (Exception)
                            {
                                throw new CastArgsException();
                            }
                            return method.Invoke(obj_, args_ ?? args);
                        };
                    }
                    else
                    {
                        methodInfo.method = CreateCall(method);
                    }
                    Type returnType = method.ReturnType;
                    string returnTypeName = returnType.Name;
                    if ("Task" == returnTypeName || "Task`1" == returnTypeName)
                    {
                        methodInfo.isTask = true;
                        MethodInfo getResult = returnType.GetMethod("get_Result");
                        if (null != getResult)
                        {
                            methodInfo.getResult = dynamicInvoke ? (object task, object[] args) => getResult.Invoke(task, args) : CreateCall(getResult);
                        }
                    }
                    else if ("ValueTask" == returnTypeName || "ValueTask`1" == returnTypeName)
                    {
                        MethodInfo asTask = returnType.GetMethod("AsTask");
                        MethodInfo getResult = returnType.GetMethod("GetResult");
                        methodInfo.valueTask = dynamicInvoke ? (object task, object[] args) => asTask.Invoke(task, args) : CreateCall(asTask);
                        methodInfo.getResult = dynamicInvoke ? (object task, object[] args) => getResult.Invoke(task, args) : CreateCall(getResult);
                    }
                    string methodName = allowBind?.rename ?? method.Name;
                    LinkedList<BindObjInfo> sameName;
                    if (!overrideMethod.TryGetValue(methodName, out sameName))
                    {
                        sameName = new LinkedList<BindObjInfo>();
                        overrideMethod.Add(methodName, sameName);
                        Func<async_result_wrap<object, ReplyState>, object[], Task> handler = async delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                        {
                            bool countError = true;
                            foreach (BindObjInfo item in sameName)
                            {
                                if (item.argsCount != args.Length)
                                {
                                    continue;
                                }
                                try
                                {
                                    countError = false;
                                    if (item.isTask)
                                    {
                                        Task task = (Task)item.method(obj, args);
                                        await task;
                                        if (null != item.getResult)
                                        {
                                            resWrap.value1 = item.getResult(task, new object[0]);
                                        }
                                    }
                                    else if (null != item.valueTask)
                                    {
                                        object result = item.method(obj, args);
                                        Task task = (Task)item.valueTask(result, new object[0]);
                                        if (null != task)
                                        {
                                            await task;
                                        }
                                        resWrap.value1 = item.getResult(result, new object[0]);
                                    }
                                    else
                                    {
                                        resWrap.value1 = await generator.send_task(() => item.method(obj, args));
                                    }
                                    return;
                                }
                                catch (CastArgsException) { }
                                catch (ArgumentException) { }
                            }
                            resWrap.value2 = countError ? ReplyState.ArgsCountError : ReplyState.ArgsTypeError;
                        };
                        allBinds.AddLast(tuple.make($"{name}.{methodName}", handler));
                    }
                    sameName.AddLast(methodInfo);
                }
                FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
                for (int i = 0; i < fields.Length; i++)
                {
                    FieldInfo field = fields[i];
                    if (null == obj && !field.IsStatic)
                    {
                        continue;
                    }
                    AllowBind allowBind = null;
                    if (checkBindAttr && null == (allowBind = (AllowBind)Attribute.GetCustomAttribute(field, typeof(AllowBind))))
                    {
                        continue;
                    }
                    string fieldName = allowBind?.rename ?? field.Name;
                    if (null == allowBind || allowBind.getter)
                    {
                        Func<object, object> getValue = dynamicInvoke ? (object obj_) => field.GetValue(obj_) : CreateObjectGetter(field);
                        Func<async_result_wrap<object, ReplyState>, object[], Task> handler = delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                        {
                            if (0 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            resWrap.value1 = getValue(obj);
                            return generator.non_async();
                        };
                        allBinds.AddLast(tuple.make($"{name}.get@{fieldName}", handler));
                    }
                    if (null == allowBind || allowBind.setter)
                    {
                        Action<object, object> setValue;
                        if (!dynamicInvoke)
                        {
                            setValue = CreateObjectSetter(field, true);
                        }
                        else if (!ParamTuple.IsParam(field.FieldType, false))
                        {
                            setValue = (object obj_, object value) => field.SetValue(obj_, value);
                        }
                        else
                        {
                            setValue = delegate (object obj_, object value)
                            {
                                ParamTuple paramTuple = (ParamTuple)Activator.CreateInstance(field.FieldType);
                                paramTuple.Objects = (ParamTuple.Serialize)value;
                                field.SetValue(obj_, paramTuple);
                            };
                        }
                        Func<async_result_wrap<object, ReplyState>, object[], Task> handler = delegate (async_result_wrap<object, ReplyState> resWrap, object[] args)
                        {
                            if (1 != args.Length)
                            {
                                resWrap.value2 = ReplyState.ArgsCountError;
                                return generator.non_async();
                            }
                            try
                            {
                                setValue(obj, args[0]);
                            }
                            catch (InvalidCastException)
                            {
                                resWrap.value2 = ReplyState.ArgsTypeError;
                            }
                            catch (CastArgsException)
                            {
                                resWrap.value2 = ReplyState.ArgsTypeError;
                            }
                            catch (ArgumentException)
                            {
                                resWrap.value2 = ReplyState.ArgsTypeError;
                            }
                            return generator.non_async();
                        };
                        allBinds.AddLast(tuple.make($"{name}.set@{fieldName}", handler));
                    }
                }
                int idx = 0;
                string[] names = new string[allBinds.Count];
                foreach (var item in allBinds)
                {
                    names[idx++] = item.value1;
                    Add(item.value1, item.value2, runStrand);
                }
                return names;
            }

            private void Add(string name, Func<async_result_wrap<object, ReplyState>, object[], Task> handler, shared_strand runStrand)
            {
                if (!_methodsMap.TryAdd(name, tuple.make(handler, runStrand)))
                {
                    throw new Exception($"绑定重复的方法名 {name}");
                }
            }

            internal bool Get(string name, out tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand> handler)
            {
                return _methodsMap.TryGetValue(name, out handler);
            }

            public bool Remove(string name)
            {
                return _methodsMap.TryRemove(name, out var _);
            }

            public void Remove(params string[] names)
            {
                foreach (var name in names)
                {
                    Remove(name);
                }
            }

            public void Clear()
            {
                _methodsMap.Clear();
            }
        }

        public class RpcException : Exception
        {
            public ReplyState code;

            public RpcException(ReplyState st)
            {
                code = st;
            }
        }

        public struct Result
        {
            public ReplyState state;
            public string message;
            public object result;

            static public implicit operator ReplyState(Result rval)
            {
                return rval.state;
            }

            public void Check()
            {
                if (ReplyState.Success != state)
                {
                    throw new RpcException(state);
                }
            }

            public bool Success
            {
                get
                {
                    return state == ReplyState.Success;
                }
            }
        }

        public struct Result<R>
        {
            public ReplyState state;
            public string message;
            public R result;

            static public implicit operator R(Result<R> rval)
            {
                rval.Check();
                return rval.result;
            }

            static public implicit operator ReplyState(Result<R> rval)
            {
                return rval.state;
            }

            public void Check()
            {
                if (ReplyState.Success != state)
                {
                    throw new RpcException(state);
                }
            }

            public bool Success
            {
                get
                {
                    return state == ReplyState.Success;
                }
            }
        }

        class OverSend
        {
            public bool closed;
            public wait_group wg;
            public LinkedList<tuple<Func<bool, ValueTask>, RecvName>> actions;

            public OverSend()
            {
                closed = false;
                wg = new wait_group(1);
                actions = new LinkedList<tuple<Func<bool, ValueTask>, RecvName>>();
            }

            public RecvName[] Sends()
            {
                if (0 == actions.Count)
                {
                    return null;
                }
                RecvName[] sends = new RecvName[actions.Count];
                int num = 0;
                foreach (var item in actions)
                {
                    if (item.value2.count >= 0)
                    {
                        sends[num++] = item.value2;
                    }
                }
                if (0 == num)
                {
                    return null;
                }
                if (sends.Length == num)
                {
                    return sends;
                }
                RecvName[] sends_ = new RecvName[num];
                Array.Copy(sends, sends_, num);
                return sends_;
            }

            public void Close()
            {
                closed = true;
                wg.done();
            }
        }

        public struct RpcCancel
        {
            internal wait_group wg;

            public bool Nil
            {
                get
                {
                    return null == wg;
                }
            }

            public void AppendNotify(Action notify)
            {
                wg.async_wait(notify);
            }

            public Task Wait()
            {
                return generator.wait_group(wg);
            }

            public ValueTask<bool> Wait(int ms)
            {
                return generator.timed_wait_group(ms, wg);
            }
        }

        public struct OverCancel
        {
            internal wait_group wg;

            static internal OverCancel Make()
            {
                return new OverCancel
                {
                    wg = new wait_group(1)
                };
            }

            public bool Nil
            {
                get
                {
                    return null == wg;
                }
            }

            public void Cancel()
            {
                wg.force();
            }
        }

        public class CancelException : Exception
        {
            internal CancelException() { }
        }

        [Serializable]
        internal struct RecvName
        {
            public long id;
            public long count;
            public int segment;
        }

        public class OverRecv
        {
            internal OverRecv(RecvName recvName)
            {
                _id = recvName.id;
                _count = recvName.count;
                _segment = recvName.segment;
                _multiSign = 0;
                _index = -1;
                _cancel = false;
            }

            internal long _id;
            internal long _offset;
            internal long _count;
            internal int _index;
            internal int _segment;
            internal int _multiSign;
            internal bool _cancel;

            public bool Cancel => _cancel;
            public bool Big => Length > int.MaxValue;
            public bool Full => _offset == _count;
            public long Offset => _offset;
            public long Length => _count;
            public int Segment => _segment;
            public int Index => _index;
        }

        class OverSendState
        {
            public class ResultException : Exception
            {
                internal ResultException() { }
            }

            public class CountException : Exception
            {
                internal CountException() { }
            }

            public SendName name;
            public long maxCount;
            public long count;
            public ValueTask<csp_invoke_wrap<void_type>> task;
        }

        internal class SendName
        {
            static long _inc = 0;
            public long _id;
            public bool _done;

            public SendName()
            {
                _id = Interlocked.Increment(ref _inc);
            }
        }

        public class RecvDoubleBuffer
        {
            shared_strand work;
            wait_group task;
            byte[] buff1;
            byte[] buff2;
            bool error;

            public RecvDoubleBuffer(int size)
                : this(size, new shared_strand()) { }

            public RecvDoubleBuffer(int size, shared_strand backWork)
            {
                work = backWork;
                task = new wait_group();
                buff1 = new byte[size];
                buff2 = new byte[size];
                error = false;
            }

            public void Async(Action handler)
            {
                Debug.Assert(task.is_done, "RecvDoubleBuffer 异步任务未结束");
                error = false;
                task.add();
                work.post(delegate ()
                {
                    try
                    {
                        handler();
                    }
                    catch (Exception)
                    {
                        error = true;
                    }
                    finally
                    {
                        task.done();
                    }
                });
            }

            public async Task Exchange()
            {
                await task.wait();
                byte[] temp = buff1;
                buff1 = buff2;
                buff2 = temp;
            }

            public byte[] WriteData
            {
                get
                {
                    return buff1;
                }
            }

            public byte[] RecvBuff
            {
                get
                {
                    return buff2;
                }
            }

            public bool Error
            {
                get
                {
                    return error;
                }
            }
        }

        public class SendDoubleBuffer
        {
            shared_strand work;
            wait_group task;
            byte[] buff1;
            byte[] buff2;
            int count;
            bool error;

            public SendDoubleBuffer(int size)
                : this(size, new shared_strand()) { }

            public SendDoubleBuffer(int size, shared_strand backWork)
            {
                work = backWork;
                task = new wait_group();
                buff1 = new byte[size];
                buff2 = new byte[size];
                count = 0;
                error = false;
            }

            public void Async(Func<int> handler)
            {
                Debug.Assert(task.is_done, "SendDoubleBuffer 异步任务未结束");
                count = 0;
                error = false;
                task.add();
                work.post(delegate ()
                {
                    try
                    {
                        count = handler();
                    }
                    catch (Exception)
                    {
                        error = true;
                    }
                    finally
                    {
                        task.done();
                    }
                });
            }

            public async Task Exchange()
            {
                await task.wait();
                byte[] temp = buff1;
                buff1 = buff2;
                buff2 = temp;
            }

            public byte[] ReadBuff
            {
                get
                {
                    return buff1;
                }
            }

            public ArraySegment<byte> SendData
            {
                get
                {
                    return new ArraySegment<byte>(buff2, 0, count);
                }
            }

            public bool Error
            {
                get
                {
                    return error;
                }
            }
        }

        public class Session
        {
            public enum ExitCode
            {
                Undefined,
                LocalClose,
                RemoteClose,
                SessionClose,
                SocketClosed,
                KeepOvertime,
                RecvKeepOvertime,
                RecvBinOvertime,
                SendBinOvertime,
                DataHeadError,
                ReplySerializeError,
                RequestSerializeError,
                ReplyDeserializeError,
                RequestDeserializeError,
            }

            struct SendByteParam
            {
                public SendName name;
                public int timed;
                public int index;
                public ArraySegment<byte> data;
            }

            struct SendPtrParam
            {
                public SendName name;
                public int timed;
                public int index;
                public IntPtr pointer;
                public long offset;
                public int count;
            }

            struct SendFileParam
            {
                public SendName name;
                public int timed;
                public int index;
                public SafeHandle file;
                public long offset;
                public int count;
            }

            struct RpcParam
            {
                public long id;
                public int timed;
                public object[] args;
                public Request request;
                public OverSend overSend;
                public OverCancel overCancel;
            }

            struct RecvPtrParam
            {
                public int timed;
                public IntPtr pointer;
                public long offset;
                public int count;
            }

            struct RecvByteParam
            {
                public int timed;
                public ArraySegment<byte> buff;
            }

            struct NamedRecvParam
            {
                public OverRecv name;
                public NamedCsp csp;
            }

            struct RecvList
            {
                public OverRecv[] recvs;
            }

            struct OverCallbackList
            {
                public LinkedList<string> names;
            }

            enum NamedType
            {
                Byte,
                Ptr
            }

            interface NamedCsp
            {
                NamedType Type { get; }
                void Close();
            }

            class NamedByteCsp : csp_chan<int, RecvByteParam>, NamedCsp
            {
                public NamedByteCsp(shared_strand strand) : base(strand) { }
                public NamedType Type => NamedType.Byte;
                public void Close() => base.close();
            }

            class NamedPtrCsp : csp_chan<int, RecvPtrParam>, NamedCsp
            {
                public NamedPtrCsp(shared_strand strand) : base(strand) { }
                public NamedType Type => NamedType.Ptr;
                public void Close() => base.close();
            }

            static generator.local<Session> _session = new generator.local<Session>();
            static byte[] _lostBinBuff = new byte[1024 * 1024];
            static long _idCount = DateTime.Now.Ticks;
            static int _keep = 10000;

            int _exitCode;
            socket _socket;
            Methods _methods;
            generator _action;
            shared_strand[] _strands;
            generator.local<OverSend> _overSend;
            generator.local<RecvList> _recvList;
            generator.local<RpcCancel> _rpcCancel;
            generator.local<OverCancel> _overCancel;
            generator.local<OverSendState> _overSendState;
            generator.local<OverCallbackList> _overCallbackList;
            csp_chan<Result, RpcParam> _rpcChan;
            csp_chan<void_type, SendName> _cancelSendChan;
            csp_chan<void_type, SendByteParam> _sendByteChan;
            csp_chan<void_type, SendPtrParam> _sendPtrChan;
            csp_chan<void_type, SendFileParam> _sendFileChan;
            csp_chan<int, RecvPtrParam> _recvPtrChan;
            csp_chan<int, RecvByteParam> _recvByteChan;
            chan<NamedRecvParam> _namedRecvChan;
            chan<DataType> _remoteCmdChan;
            chan<long> _cancelRpcChan;

            public Session(shared_strand[] strands, socket socket, Methods methods)
            {
                Debug.Assert((socket is socket_tcp) || (socket is socket_pipe), "Rpc.Session 只能为 socket_tcp 或 socket_pipe");
                _socket = socket;
                _methods = methods;
                _strands = strands;
                _exitCode = (int)ExitCode.Undefined;
                _overSend = new generator.local<OverSend>();
                _recvList = new generator.local<RecvList>();
                _rpcCancel = new generator.local<RpcCancel>();
                _overCancel = new generator.local<OverCancel>();
                _overSendState = new generator.local<OverSendState>();
                _overCallbackList = new generator.local<OverCallbackList>();
                _rpcChan = new csp_chan<Result, RpcParam>(_strands[0]);
                _cancelSendChan = new csp_chan<void_type, SendName>(_strands[0]);
                _sendByteChan = new csp_chan<void_type, SendByteParam>(_strands[0]);
                _sendPtrChan = new csp_chan<void_type, SendPtrParam>(_strands[0]);
                _sendFileChan = new csp_chan<void_type, SendFileParam>(_strands[0]);
                _recvPtrChan = new csp_chan<int, RecvPtrParam>(_strands[0]);
                _recvByteChan = new csp_chan<int, RecvByteParam>(_strands[0]);
                _namedRecvChan = chan<NamedRecvParam>.make(_strands[0], -1);
                _remoteCmdChan = chan<DataType>.make(_strands[0], -1);
                _cancelRpcChan = chan<long>.make(_strands[0], -1);
                _action = generator.make(_strands[0], () => Run(), delegate ()
                {
                    _socket.close();
                    _rpcChan.close();
                    _cancelSendChan.close();
                    _sendByteChan.close();
                    _sendPtrChan.close();
                    _sendFileChan.close();
                    _recvPtrChan.close();
                    _recvByteChan.close();
                    _namedRecvChan.close();
                    _remoteCmdChan.close();
                    _cancelRpcChan.close();
                });
            }

            public Session(shared_strand strand, socket socket, Methods methods)
                : this(new shared_strand[] { strand }, socket, methods) { }

            public void Start()
            {
                _action.run();
            }

            public void Close()
            {
                _action.stop();
            }

            public void AppendNotify(Action notify)
            {
                _action.append_stop_callback(notify);
            }

            public Task Wait()
            {
                return generator.wait_other(_action);
            }

            public ValueTask<bool> Wait(int ms)
            {
                return generator.timed_wait_other(ms, _action);
            }

            public bool Closed
            {
                get
                {
                    return _action.is_completed();
                }
            }

            public ExitCode Code
            {
                get
                {
                    return (ExitCode)_exitCode;
                }
            }

            public Methods Methods
            {
                get
                {
                    return _methods;
                }
            }

            static private void Swap<T>(ref T a, ref T b)
            {
                T t = a;
                a = b;
                b = t;
            }

            static private int Read32(byte[] buff, int offset)
            {
                return (buff[offset + 0] << (0 * 8))
                 | (buff[offset + 1] << (1 * 8))
                 | (buff[offset + 2] << (2 * 8))
                 | (buff[offset + 3] << (3 * 8));
            }

            static private long Read64(byte[] buff, int offset)
            {
                return ((long)buff[offset + 0] << (0 * 8))
                 | ((long)buff[offset + 1] << (1 * 8))
                 | ((long)buff[offset + 2] << (2 * 8))
                 | ((long)buff[offset + 3] << (3 * 8))
                 | ((long)buff[offset + 4] << (4 * 8))
                 | ((long)buff[offset + 5] << (5 * 8))
                 | ((long)buff[offset + 6] << (6 * 8))
                 | ((long)buff[offset + 7] << (7 * 8));
            }

            static private void Write32(int val, byte[] buff, int offset)
            {
                buff[offset + 0] = (byte)(val >> (0 * 8));
                buff[offset + 1] = (byte)(val >> (1 * 8));
                buff[offset + 2] = (byte)(val >> (2 * 8));
                buff[offset + 3] = (byte)(val >> (3 * 8));
            }

            static private void Write64(long val, byte[] buff, int offset)
            {
                buff[offset + 0] = (byte)(val >> (0 * 8));
                buff[offset + 1] = (byte)(val >> (1 * 8));
                buff[offset + 2] = (byte)(val >> (2 * 8));
                buff[offset + 3] = (byte)(val >> (3 * 8));
                buff[offset + 4] = (byte)(val >> (4 * 8));
                buff[offset + 5] = (byte)(val >> (5 * 8));
                buff[offset + 6] = (byte)(val >> (6 * 8));
                buff[offset + 7] = (byte)(val >> (7 * 8));
            }

            static private void ReadHead(byte[] recvHead, out long id, out int len1, out int len2, out DataType type)
            {
                id = Read64(recvHead, 0);
                len1 = Read32(recvHead, 8);
                len2 = Read32(recvHead, 12);
                type = (DataType)recvHead[16];
            }

            static private void WriteHead(byte[] sendHead, long id, int len1, int len2, DataType type)
            {
                Write64(id, sendHead, 0);
                Write32(len1, sendHead, 8);
                Write32(len2, sendHead, 12);
                sendHead[16] = (byte)type;
            }

            static public Session Self
            {
                get
                {
                    _session.get(out Session self);
                    return self;
                }
            }

            static public RpcCancel CancelWait()
            {
                Session self = Self;
                Debug.Assert(null != self, "不在 Rpc.Session 上下文中");
                self._rpcCancel.get(out RpcCancel value);
                return value;
            }

            static public OverRecv[] OverRecv()
            {
                Session self = Self;
                Debug.Assert(null != self, "不在 Rpc.Session 上下文中");
                if (!self._recvList.get(out RecvList value))
                {
                    return null;
                }
                return value.recvs;
            }

            static public void ThrowCancel()
            {
                Session self = Self;
                Debug.Assert(null != self, "不在 Rpc.Session 上下文中");
                throw new CancelException();
            }

            static public void DisableKeep()
            {
                _keep = -1;
            }

            public async Task DiscardRecv(OverRecv[] recvs)
            {
                if (null == recvs)
                {
                    return;
                }
                generator.lock_shield();
                for (int i = 0; i < recvs.Length; i++)
                {
                    while (!recvs[i].Full && !recvs[i].Cancel)
                    {
                        await Recv(recvs[i], _lostBinBuff, 0, _lostBinBuff.Length);
                    }
                }
                await generator.unlock_shield();
            }

            public async Task DiscardChaoticRecv(params OverRecv[] recvs)
            {
                if (null == recvs)
                {
                    return;
                }
                generator.lock_shield();
                generator.children children = new generator.children();
                children.ignore_suspend();
                for (int i = 0; i < recvs.Length; i++)
                {
                    int j = i;
                    children.go(async delegate ()
                    {
                        while (!recvs[j].Full && !recvs[j].Cancel)
                        {
                            await Recv(recvs[j], _lostBinBuff, 0, _lostBinBuff.Length);
                        }
                    });
                }
                await children.wait_all();
                await generator.unlock_shield();
            }

            public OverCancel OverCancel()
            {
                Debug.Assert(!_overCancel.get(out _), "重复的 OverCancel");
                OverCancel call = Rpc.OverCancel.Make();
                _overCancel.value = call;
                return call;
            }

            public void ClearOverSend()
            {
                _overSend.remove(out _);
            }

            private void OverSend(Func<bool, ValueTask> action, SendName name, long count, int segment)
            {
                if (!_overSend.get(out OverSend send))
                {
                    send = new OverSend();
                    _overSend.value = send;
                }
                send.actions.AddLast(tuple.make(action, new RecvName { id = name._id, count = count, segment = segment }));
            }

            private void OverSend(Func<bool, Task> action, SendName name, long count, int segment)
            {
                OverSend((bool cancel) => new ValueTask(action(cancel)), name, count, segment);
            }

            private void OverSend(Func<bool, ValueTask<csp_invoke_wrap<void_type>>> action, SendName name, long count, int segment)
            {
                OverSend((bool cancel) => new ValueTask(action(cancel).AsTask()), name, count, segment);
            }

            private ValueTask<csp_invoke_wrap<void_type>> CancelSend(SendName name)
            {
                return generator.csp_invoke(_cancelSendChan, name);
            }

            private OverSendState CheckOverSendState(int count)
            {
                if (_overSendState.get(out OverSendState sendState))
                {
                    if (!sendState.task.IsCompleted)
                    {
                        throw new OverSendState.ResultException();
                    }
                    if (count > sendState.maxCount)
                    {
                        throw new OverSendState.CountException();
                    }
                    sendState.count += count;
                    sendState.maxCount -= count;
                }
                else
                {
                    Debug.Assert(false, "错误的 Send");
                }
                return sendState;
            }

            public void OverSend(long count, Func<long, long, ValueTask<csp_invoke_wrap<void_type>>> sendAction)
            {
                OverSend(count, (long offset_, long count_) => sendAction(offset_, count_).AsTask() ?? generator.non_async());
            }

            public void OverSend(long count, Func<long, long, Task> sendAction)
            {
                SendName name = new SendName { _done = count <= 0 };
                OverSend(async delegate (bool cancel)
                {
                    if (cancel)
                    {
                        await CancelSend(name);
                        return;
                    }
                    try
                    {
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        for (long off = 0; off < count;)
                        {
                            if (0 != off)
                            {
                                generator.lock_stop();
                            }
                            sendState.count = 0;
                            sendState.maxCount = count - off;
                            await sendAction(off, count - off);
                            if (!sendState.task.IsCompleted)
                            {
                                throw new OverSendState.ResultException();
                            }
                            chan_state state = sendState.task.Result;
                            long len = sendState.count;
                            if (len <= 0)
                            {
                                await CancelSend(name);
                                break;
                            }
                            if (state != chan_state.ok)
                            {
                                await CancelSend(name);
                                break;
                            }
                            off += len;
                            if (count != off)
                            {
                                generator.unlock_stop();
                            }
                        }
                        name._done = true;
                    }
                    catch (OverSendState.ResultException)
                    {
                        Close();
                        Debug.Assert(false, "OverSend 发送异步结果未结束");
                    }
                    catch (OverSendState.CountException)
                    {
                        Close();
                        Debug.Assert(false, "OverSend 发送长度溢出");
                    }
                    catch (generator.stop_exception)
                    {
                        await CancelSend(name);
                        throw;
                    }
                }, name, count, 0);
            }

            public void OverSend(ArraySegment<byte> data, int segment = 0)
            {
                OverTimedSend(-1, data, segment);
            }

            public void OverSend(byte[] data, int offset, int count, int segment = 0)
            {
                OverTimedSend(-1, data, offset, count, segment);
            }

            public void OverSend(IntPtr pointer, long offset, long count, int segment = 0)
            {
                OverTimedSend(-1, pointer, offset, count, segment);
            }

            public void OverSend(SafeHandle file, long offset, long count, int segment = 0)
            {
                OverTimedSend(-1, file, offset, count, segment);
            }

            public void OverTimedSend(int timed, ArraySegment<byte> data, int segment = 0)
            {
                SendName name = new SendName { _done = data.Count <= 0 };
                if (segment > 0 && segment < data.Count)
                {
                    OverSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelSend(name);
                            return;
                        }
                        try
                        {
                            segment = segment <= 0 ? data.Count : segment;
                            OverSendState sendState = _overSendState.value;
                            sendState.name = name;
                            int index = 0;
                            for (int off = 0; off < data.Count; index++)
                            {
                                int len = Math.Min(data.Count - off, segment);
                                if (0 != off)
                                {
                                    generator.lock_stop();
                                }
                                sendState.count = 0;
                                sendState.maxCount = data.Count - off;
                                chan_state state = await TimedSend(tuple.make(-1, timed), new ArraySegment<byte>(data.Array, data.Offset + off, len), index);
                                if (state != chan_state.ok)
                                {
                                    return;
                                }
                                off += len;
                                if (data.Count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                            name._done = true;
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelSend(name);
                            throw;
                        }
                    }, name, data.Count, segment);
                }
                else
                {
                    OverSend(delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            return CancelSend(name);
                        }
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        sendState.count = 0;
                        sendState.maxCount = data.Count;
                        return TimedSend(tuple.make(-1, timed), data);
                    }, name, data.Count, 0);
                }
            }

            public void OverTimedSend(int timed, byte[] data, int offset, int count, int segment = 0)
            {
                OverTimedSend(timed, new ArraySegment<byte>(data, offset, count), segment);
            }

            public void OverTimedSend(int timed, IntPtr pointer, long offset, long count, int segment = 0)
            {
                SendName name = new SendName { _done = count <= 0 };
                if (segment <= 0 && count > int.MaxValue)
                {
                    segment = int.MaxValue;
                }
                if (segment > 0 && segment < count)
                {
                    OverSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelSend(name);
                            return;
                        }
                        try
                        {
                            segment = segment <= 0 ? (int)Math.Min(int.MaxValue, count) : segment;
                            OverSendState sendState = _overSendState.value;
                            sendState.name = name;
                            int index = 0;
                            for (long off = 0; off < count; index++)
                            {
                                int len = (int)Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    generator.lock_stop();
                                }
                                sendState.count = 0;
                                sendState.maxCount = count - off;
                                chan_state state = await TimedSend(tuple.make(-1, timed), new IntPtr(pointer.ToInt64() + offset + off), 0, len, index);
                                if (state != chan_state.ok)
                                {
                                    return;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                            name._done = true;
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelSend(name);
                            throw;
                        }
                    }, name, count, segment);
                }
                else
                {
                    OverSend(delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            return CancelSend(name);
                        }
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        sendState.count = 0;
                        sendState.maxCount = count;
                        return TimedSend(tuple.make(-1, timed), new IntPtr(pointer.ToInt64() + offset), 0, (int)count);
                    }, name, count, 0);
                }
            }

            public void OverTimedSend(int timed, SafeHandle file, long offset, long count, int segment = 0)
            {
                SendName name = new SendName { _done = count <= 0 };
                if (segment <= 0 && count > int.MaxValue)
                {
                    segment = int.MaxValue;
                }
                if (segment > 0 && segment < count)
                {
                    OverSend(async delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            await CancelSend(name);
                            return;
                        }
                        try
                        {
                            segment = segment <= 0 ? (int)Math.Min(int.MaxValue, count) : segment;
                            OverSendState sendState = _overSendState.value;
                            sendState.name = name;
                            int index = 0;
                            for (long off = 0; off < count; index++)
                            {
                                int len = (int)Math.Min(count - off, segment);
                                if (0 != off)
                                {
                                    generator.lock_stop();
                                }
                                sendState.count = 0;
                                sendState.maxCount = count - off;
                                chan_state state = await TimedSend(tuple.make(-1, timed), file, offset + off, len, index);
                                if (state != chan_state.ok)
                                {
                                    return;
                                }
                                off += len;
                                if (count != off)
                                {
                                    generator.unlock_stop();
                                }
                            }
                            name._done = true;
                        }
                        catch (generator.stop_exception)
                        {
                            await CancelSend(name);
                            throw;
                        }
                    }, name, count, segment);
                }
                else
                {
                    OverSend(delegate (bool cancel)
                    {
                        if (cancel)
                        {
                            return CancelSend(name);
                        }
                        OverSendState sendState = _overSendState.value;
                        sendState.name = name;
                        sendState.count = 0;
                        sendState.maxCount = count;
                        return TimedSend(tuple.make(-1, timed), file, offset, (int)count);
                    }, name, count, 0);
                }
            }

            public void OverHandler(Func<Task> handler)
            {
                SendName name = new SendName { _done = true };
                OverSend(delegate (bool cancel)
                {
                    if (cancel)
                    {
                        return generator.non_async();
                    }
                    return handler();
                }, name, -1, 0);
            }

            public void CancelOverSend()
            {
                _overSend.remove();
            }

            private void CheckOverCallback(params string[] names)
            {
                if (!_overCallbackList.get(out OverCallbackList callbackList))
                {
                    callbackList.names = new LinkedList<string>();
                    _overCallbackList.value = callbackList;
                }
                foreach (var name in names)
                {
                    callbackList.names.AddLast(name);
                }
            }

            public void ClearCallback()
            {
                if (_overCallbackList.get(out OverCallbackList callbackList))
                {
                    while (0 != callbackList.names.Count)
                    {
                        Methods.Remove(callbackList.names.First.Value);
                        callbackList.names.RemoveFirst();
                    }
                }
            }

            public Methods.Name OverCallback(Func<object[], Task> callback, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                Methods.Bind(name, callback, runStrand ?? generator.self_strand());
                CheckOverCallback(name);
                return name;
            }

            public Methods.Name OverCallback(Func<object[], ValueTask> callback, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                Methods.Bind(name, callback, runStrand ?? generator.self_strand());
                CheckOverCallback(name);
                return name;
            }

            public Methods.Name OverCallback(Func<object[], ValueTask<void_type>> callback, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                Methods.Bind(name, callback, runStrand ?? generator.self_strand());
                CheckOverCallback(name);
                return name;
            }

            public Methods.Name OverCallback<R>(Func<object[], Task<R>> callback, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                Methods.Bind(name, callback, runStrand ?? generator.self_strand());
                CheckOverCallback(name);
                return name;
            }

            public Methods.Name OverCallback<R>(Func<object[], ValueTask<R>> callback, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                Methods.Bind(name, callback, runStrand ?? generator.self_strand());
                CheckOverCallback(name);
                return name;
            }

            public Methods.Name OverCallback(Action<object[]> callback, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                Methods.Bind(name, callback, runStrand ?? generator.self_strand());
                CheckOverCallback(name);
                return name;
            }

            public Methods.Name OverCallback<R>(Func<object[], R> callback, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                Methods.Bind(name, callback, runStrand ?? generator.self_strand());
                CheckOverCallback(name);
                return name;
            }

            public Methods.Name OverCallback(Delegate callback, shared_strand runStrand = null, bool dynamicInvoke = true)
            {
                Methods.Name name = Methods.GenName;
                Methods.Bind(name, callback, runStrand ?? generator.self_strand(), dynamicInvoke);
                CheckOverCallback(name);
                return name;
            }

            public Methods.Name OverStatic(Type type, bool checkBindAttr, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                string[] names = Methods.BindStatic(name, type, checkBindAttr, runStrand ?? generator.self_strand());
                CheckOverCallback(names);
                return name;
            }

            public Methods.Name OverObj<T>(T obj, bool checkBindAttr, shared_strand runStrand = null)
            {
                Methods.Name name = Methods.GenName;
                string[] names = Methods.BindObj(name, obj, checkBindAttr, runStrand ?? generator.self_strand());
                CheckOverCallback(names);
                return name;
            }

            public async Task<Result> Call(int timed, string name, params object[] args)
            {
                long requestId = 0;
                generator sendAction = null;
                _overSend.remove(out OverSend overSend);
                _overCancel.remove(out OverCancel overCancel);
                try
                {
                    if (_rpcChan.closed)
                    {
                        return new Result { state = ReplyState.Fail };
                    }
                    if (!overCancel.Nil && overCancel.wg.is_done)
                    {
                        return new Result { state = ReplyState.LocalCancel };
                    }
                    if (null != overSend && overSend.actions.Count > 0)
                    {
                        generator.go(out sendAction, generator.self_strand(), async delegate ()
                        {
                            try
                            {
                                _session.value = this;
                                generator.lock_stop();
                                await overSend.wg.wait();
                                if (overSend.closed)
                                {
                                    overSend.actions.Clear();
                                }
                                generator.unlock_stop();
                                _overSendState.value = new OverSendState();
                                while (overSend.actions.Count > 0)
                                {
                                    generator.lock_stop();
                                    var item = overSend.actions.First.Value;
                                    overSend.actions.RemoveFirst();
                                    await item.value1(false);
                                    generator.unlock_stop();
                                }
                            }
                            catch (generator.stop_exception)
                            {
                                while (overSend.actions.Count > 0)
                                {
                                    var item = overSend.actions.First.Value;
                                    overSend.actions.RemoveFirst();
                                    await item.value1(true);
                                }
                                throw;
                            }
                            finally
                            {
                                _overSendState.remove();
                            }
                        });
                    }
                    requestId = Interlocked.Increment(ref _idCount);
                    csp_invoke_wrap<Result> resultWrap = await generator.csp_invoke(_rpcChan, new RpcParam { id = requestId, timed = timed, args = args, overSend = overSend, overCancel = overCancel, request = new Request { name = name, sends = overSend?.Sends() } });
                    if (chan_state.ok != resultWrap.state)
                    {
                        if (chan_state.closed == resultWrap.state)
                        {
                            requestId = 0;
                            overSend?.Close();
                        }
                        return new Result { state = ReplyState.Fail };
                    }
                    switch (resultWrap.result.state)
                    {
                        case ReplyState.Overtime:
                        case ReplyState.LocalCancel:
                            return resultWrap.result;
                        default:
                            if (null != sendAction && 0 == timed && ReplyState.Success == resultWrap.result.state)
                            {
                                await generator.wait_other(sendAction);
                            }
                            requestId = 0;
                            return resultWrap.result;
                    }
                }
                catch (generator.stop_exception)
                {
                    if (null != sendAction)
                    {
                        if (_rpcChan.closed)
                        {
                            requestId = 0;
                            overSend.Close();
                        }
                        else if (!_rpcChan.strand.running_in_this_thread())
                        {
                            _rpcChan.strand.post(delegate ()
                            {
                                if (_rpcChan.closed)
                                {
                                    overSend.Close();
                                }
                            });
                        }
                    }
                    throw;
                }
                finally
                {
                    generator.lock_shield();
                    if (null != sendAction)
                    {
                        await generator.stop_other(sendAction);
                    }
                    if (0 != requestId)
                    {
                        _cancelRpcChan.post(requestId);
                    }
                    ClearCallback();
                    await generator.unlock_shield();
                }
            }

            public Task<Result> Call(string name, params object[] args)
            {
                return Call(-1, name, args);
            }

            public async Task<Result<R>> Call<R>(int ms, string name, params object[] args)
            {
                Result result = await Call(ms, name, args);
                if (result.state != ReplyState.Success)
                {
                    return new Result<R> { state = result.state, message = result.message };
                }
                try
                {
                    if (result.result is ParamTuple.Serialize)
                    {
                        ParamTuple resultObj = (ParamTuple)Activator.CreateInstance(typeof(R));
                        resultObj.Objects = (ParamTuple.Serialize)result.result;
                        return new Result<R> { state = result.state, result = (R)(object)resultObj };
                    }
                    return new Result<R> { state = result.state, result = (R)result.result };
                }
                catch (Exception)
                {
                    return new Result<R> { state = ReplyState.ResultTypeError };
                }
            }

            public Task<Result<R>> Call<R>(string name, params object[] args)
            {
                return Call<R>(-1, name, args);
            }

            public Task<Result> Post(string name, params object[] args)
            {
                return Call(0, name, args);
            }

            public void RemoteClose()
            {
                _remoteCmdChan.post(DataType.Close);
            }

            public void NoKeep()
            {
                _remoteCmdChan.post(DataType.NoKeep);
            }

            public ValueTask<csp_invoke_wrap<void_type>> Send(ArraySegment<byte> data, int index = -1)
            {
                OverSendState sendState = CheckOverSendState(data.Count);
                return sendState.task = generator.csp_invoke(_sendByteChan, new SendByteParam { name = sendState.name, timed = -1, index = index, data = data });
            }

            public ValueTask<csp_invoke_wrap<void_type>> Send(byte[] data, int offset, int count, int index = -1)
            {
                return Send(new ArraySegment<byte>(data, offset, count), index);
            }

            public ValueTask<csp_invoke_wrap<void_type>> Send(IntPtr pointer, long offset, int count, int index = -1)
            {
                Debug.Assert(_socket is socket_tcp, "指针发送只能为 socket_tcp");
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_invoke(_sendPtrChan, new SendPtrParam { name = sendState.name, timed = -1, index = index, pointer = pointer, offset = offset, count = count });
            }

            public ValueTask<csp_invoke_wrap<void_type>> Send(SafeHandle file, long offset, int count, int index = -1)
            {
                Debug.Assert(_socket is socket_tcp, "文件发送只能为 socket_tcp");
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_invoke(_sendFileChan, new SendFileParam { name = sendState.name, timed = -1, index = index, file = file, offset = offset, count = count });
            }

            public async Task<csp_invoke_wrap<int>> Recv(OverRecv name, ArraySegment<byte> buff)
            {
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    Debug.Assert(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedByteCsp recvChan = new NamedByteCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { name = name, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_invoke(recvChan, new RecvByteParam { timed = -1, buff = buff });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            public Task<csp_invoke_wrap<int>> Recv(OverRecv name, byte[] buff, int offset, int count)
            {
                return Recv(name, new ArraySegment<byte>(buff, offset, count));
            }

            public async Task<csp_invoke_wrap<int>> Recv(OverRecv name, IntPtr pointer, long offset, int count)
            {
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    Debug.Assert(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedPtrCsp recvChan = new NamedPtrCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { name = name, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_invoke(recvChan, new RecvPtrParam { timed = -1, pointer = pointer, offset = offset, count = count });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, ArraySegment<byte> data, int index = -1)
            {
                OverSendState sendState = CheckOverSendState(data.Count);
                return sendState.task = generator.csp_timed_invoke(_sendByteChan, timed, new SendByteParam { name = sendState.name, timed = -1, index = index, data = data });
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, byte[] data, int offset, int count, int index = -1)
            {
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_timed_invoke(_sendByteChan, timed, new SendByteParam { name = sendState.name, timed = -1, index = index, data = new ArraySegment<byte>(data, offset, count) });
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, IntPtr pointer, long offset, int count, int index = -1)
            {
                Debug.Assert(_socket is socket_tcp, "指针发送只能为 socket_tcp");
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_timed_invoke(_sendPtrChan, timed, new SendPtrParam { name = sendState.name, timed = -1, index = index, pointer = pointer, offset = offset, count = count });
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(int timed, SafeHandle file, long offset, int count, int index = -1)
            {
                Debug.Assert(_socket is socket_tcp, "文件发送只能为 socket_tcp");
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_timed_invoke(_sendFileChan, timed, new SendFileParam { name = sendState.name, timed = -1, index = index, file = file, offset = offset, count = count });
            }

            public async Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, ArraySegment<byte> buff)
            {
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    Debug.Assert(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedByteCsp recvChan = new NamedByteCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { name = name, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed, new RecvByteParam { timed = -1, buff = buff });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, byte[] buff, int offset, int count)
            {
                return TimedRecv(name, timed, new ArraySegment<byte>(buff, offset, count));
            }

            public async Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, int timed, IntPtr pointer, long offset, int count)
            {
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    Debug.Assert(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedPtrCsp recvChan = new NamedPtrCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { name = name, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed, new RecvPtrParam { timed = -1, pointer = pointer, offset = offset, count = count });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, ArraySegment<byte> data, int index = -1)
            {
                OverSendState sendState = CheckOverSendState(data.Count);
                return sendState.task = generator.csp_timed_invoke(_sendByteChan, timed.value1, new SendByteParam { name = sendState.name, timed = timed.value2, index = index, data = data });
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, byte[] data, int offset, int count, int index = -1)
            {
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_timed_invoke(_sendByteChan, timed.value1, new SendByteParam { name = sendState.name, timed = timed.value2, index = index, data = new ArraySegment<byte>(data, offset, count) });
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, IntPtr pointer, long offset, int count, int index = -1)
            {
                Debug.Assert(_socket is socket_tcp, "指针发送只能为 socket_tcp");
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_timed_invoke(_sendPtrChan, timed.value1, new SendPtrParam { name = sendState.name, timed = timed.value2, index = index, pointer = pointer, offset = offset, count = count });
            }

            public ValueTask<csp_invoke_wrap<void_type>> TimedSend(tuple<int, int> timed, SafeHandle file, long offset, int count, int index = -1)
            {
                Debug.Assert(_socket is socket_tcp, "文件发送只能为 socket_tcp");
                OverSendState sendState = CheckOverSendState(count);
                return sendState.task = generator.csp_timed_invoke(_sendFileChan, timed.value1, new SendFileParam { name = sendState.name, timed = timed.value2, index = index, file = file, offset = offset, count = count });
            }

            public async Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, tuple<int, int> timed, ArraySegment<byte> buff)
            {
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    Debug.Assert(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedByteCsp recvChan = new NamedByteCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { name = name, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed.value1, new RecvByteParam { timed = timed.value2, buff = buff });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            public Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, tuple<int, int> timed, byte[] buff, int offset, int count)
            {
                return TimedRecv(name, timed, new ArraySegment<byte>(buff, offset, count));
            }

            public async Task<csp_invoke_wrap<int>> TimedRecv(OverRecv name, tuple<int, int> timed, IntPtr pointer, long offset, int count)
            {
                if (name.Full)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.ok };
                }
                if (name.Cancel)
                {
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                if (Interlocked.CompareExchange(ref name._multiSign, 1, 0) != 0)
                {
                    Debug.Assert(false, "不能多个同时 Recv");
                    return new csp_invoke_wrap<int> { state = chan_state.fail };
                }
                generator.lock_shield();
                NamedPtrCsp recvChan = new NamedPtrCsp(_namedRecvChan.strand);
                chan_state state = await generator.chan_send(_namedRecvChan, new NamedRecvParam { name = name, csp = recvChan });
                if (state != chan_state.ok)
                {
                    name._cancel = true;
                    name._multiSign = 0;
                    await generator.unlock_shield();
                    return new csp_invoke_wrap<int> { state = state };
                }
                csp_invoke_wrap<int> recvState = await generator.csp_timed_invoke(recvChan, timed.value1, new RecvPtrParam { timed = timed.value2, pointer = pointer, offset = offset, count = count });
                if (recvState.state == chan_state.ok && recvState.result >= 0)
                {
                    name._offset += recvState.result;
                }
                else
                {
                    name._cancel = true;
                }
                name._multiSign = 0;
                await generator.unlock_shield();
                return recvState;
            }

            struct ReplyMapValue
            {
                public async_timer timer;
                public csp_result<Result> result;
            }

            struct SendRequestParam
            {
                public long id;
                public object[] args;
                public Request request;
                public OverSend overSend;
            }

            struct RecvRequestParam
            {
                public long id;
                public bool cancel;
                public object[] args;
                public Request request;
            }

            struct RecvReplyParam
            {
                public long id;
                public ReplyState state;
                public object result;
                public Reply reply;
            }

            struct SendReplyParam
            {
                public long id;
                public object result;
                public Reply reply;
            }

            struct SendBuffParam
            {
                public int count;
                public OverSend overSend;
            }

            private async Task Run()
            {
                generator.children ioChild = new generator.children();
                chan_lost_msg<csp_wait_wrap<Result, RpcParam>> rpcLost = new chan_lost_msg<csp_wait_wrap<Result, RpcParam>>();
                Dictionary<long, ReplyMapValue> replyMap = new Dictionary<long, ReplyMapValue>();
                chan<SendRequestParam> sendRequestChan = chan<SendRequestParam>.make(-1);
                Action<ExitCode> setCode = (ExitCode code) => Interlocked.CompareExchange(ref _exitCode, (int)code, (int)ExitCode.Undefined);
                try
                {
                    int keep = _keep;
                    if (keep <= 0)
                    {
                        NoKeep();
                    }
                    bool isTcp = _socket is socket_tcp;
                    bool sendBin = false, recvBin = false;
                    async_timer recvTimer = new async_timer();
                    async_timer sendTimer = new async_timer();
                    chan<RecvRequestParam> recvRequestChan = chan<RecvRequestParam>.make(-1);
                    chan<RecvReplyParam> recvReplyChan = chan<RecvReplyParam>.make(-1);
                    chan<SendReplyParam> sendReplyChan = chan<SendReplyParam>.make(-1);
                    ioChild.go(async delegate ()
                    {
                        byte[] recvHead = new byte[17];
                        byte[] recvBuff1 = new byte[1024 * 1024];
                        byte[] recvBuff2 = new byte[1024 * 1024];
                        BinaryFormatter deserializer = new BinaryFormatter();
                        Map<long, NamedRecvParam> namedMap = new Map<long, NamedRecvParam>(true);
                        chan_lost_msg<NamedRecvParam> namedLost = new chan_lost_msg<NamedRecvParam>();
                        try
                        {
                            DataType lastType = DataType.Keep;
                            Action timerKeepHandler = delegate ()
                            {
                                switch (lastType)
                                {
                                    case DataType.Bin:
                                    case DataType.BinCancel:
                                        setCode(ExitCode.RecvKeepOvertime);
                                        break;
                                    default:
                                        setCode(ExitCode.KeepOvertime);
                                        break;
                                }
                                _action.stop();
                            };
                            Action timerRecvHandler = delegate ()
                            {
                                setCode(ExitCode.RecvBinOvertime);
                                _action.stop();
                            };
                            if (keep > 0)
                            {
                                recvTimer.timeout(keep, timerKeepHandler);
                            }
                            Task deserializeTask = generator.non_async();
                            while (true)
                            {
                                if (!await _socket.read(recvHead))
                                {
                                    goto socketClosed;
                                }
                                recvTimer.restart();
                                ReadHead(recvHead, out long id, out int len1, out int len2, out DataType type);
                                lastType = type;
                                switch (type)
                                {
                                    case DataType.Keep:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        break;
                                    case DataType.NoKeep:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        keep = -1;
                                        recvTimer.cancel();
                                        if (!sendBin)
                                        {
                                            sendTimer.cancel();
                                        }
                                        break;
                                    case DataType.RequestCancel:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        recvRequestChan.post(new RecvRequestParam { id = id, cancel = true });
                                        break;
                                    case DataType.Request:
                                    case DataType.Reply:
                                        if (len1 <= 0 || len2 < 0 || len1 + len2 > recvBuff1.Length)
                                        {
                                            goto dataHeadError;
                                        }
                                        if (!await _socket.read(new ArraySegment<byte>(recvBuff1, 0, len1 + len2)))
                                        {
                                            goto socketClosed;
                                        }
                                        await generator.wait_task(deserializeTask);
                                        Swap(ref recvBuff1, ref recvBuff2);
                                        (deserializeTask = new Task(delegate ()
                                        {
                                            MemoryStream stream = new MemoryStream(recvBuff2, 0, len1 + len2);
                                            switch (type)
                                            {
                                                case DataType.Request:
                                                    try
                                                    {
                                                        Request request = (Request)deserializer.Deserialize(stream);
                                                        try
                                                        {
                                                            object[] args = 0 != len2 ? (object[])deserializer.Deserialize(stream) : null;
                                                            recvRequestChan.post(new RecvRequestParam { id = id, cancel = false, args = args, request = request });
                                                        }
                                                        catch (Exception)
                                                        {
                                                            sendReplyChan.post(new SendReplyParam { id = id, reply = new Reply { state = ReplyState.RemoteDeserializeError } });
                                                            if (null != request.sends)
                                                            {
                                                                recvRequestChan.post(new RecvRequestParam { id = id, cancel = true, request = request });
                                                            }
                                                        }
                                                    }
                                                    catch (Exception)
                                                    {
                                                        setCode(ExitCode.RequestDeserializeError);
                                                        _action.stop();
                                                    }
                                                    break;
                                                case DataType.Reply:
                                                    try
                                                    {
                                                        Reply reply = (Reply)deserializer.Deserialize(stream);
                                                        try
                                                        {
                                                            object result = 0 != len2 ? deserializer.Deserialize(stream) : null;
                                                            recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Success, result = result, reply = reply });
                                                        }
                                                        catch (Exception)
                                                        {
                                                            recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Success, reply = new Reply { state = ReplyState.LocalDeserializeError } });
                                                        }
                                                    }
                                                    catch (Exception)
                                                    {
                                                        setCode(ExitCode.ReplyDeserializeError);
                                                        _action.stop();
                                                    }
                                                    break;
                                            }
                                        })).Start();
                                        break;
                                    case DataType.Bin:
                                        if (len2 <= 0)
                                        {
                                            goto dataHeadError;
                                        }
                                        {
                                            int position = 0;
                                            bool lastFind = true;
                                            while (position != len2)
                                            {
                                                var tempNode = lastFind ? namedMap.FindFirst(id) : null;
                                                if (!(lastFind = null != tempNode))
                                                {
                                                    do
                                                    {
                                                        chan_recv_wrap<NamedRecvParam> namedCsp = await _namedRecvChan.receive(namedLost);
                                                        tempNode = namedMap.Insert(namedCsp.msg.name._id, namedCsp.msg);
                                                    } while (tempNode.Key != id);
                                                }
                                                tempNode.Value.name._index = len1;
                                                switch (tempNode.Value.csp.Type)
                                                {
                                                    case NamedType.Byte:
                                                        await generator.csp_wait((NamedByteCsp)tempNode.Value.csp, async delegate (RecvByteParam param)
                                                        {
                                                            int count = param.buff.Count;
                                                            if (count > len2 - position)
                                                            {
                                                                count = len2 - position;
                                                            }
                                                            if (count <= 0)
                                                            {
                                                                recvTimer.restart();
                                                                return 0;
                                                            }
                                                            try
                                                            {
                                                                recvBin = true;
                                                                recvTimer.cancel();
                                                                if (param.timed >= 0)
                                                                {
                                                                    recvTimer.timeout(param.timed, timerRecvHandler);
                                                                }
                                                                generator.lock_stop();
                                                                socket_result result = await _socket.read(new ArraySegment<byte>(param.buff.Array, param.buff.Offset, count));
                                                                generator.unlock_stop();
                                                                if (!result)
                                                                {
                                                                    position = -1;
                                                                    return -1;
                                                                }
                                                                position += result.size;
                                                                return result.size;
                                                            }
                                                            finally
                                                            {
                                                                recvBin = false;
                                                                if (param.timed >= 0)
                                                                {
                                                                    recvTimer.cancel();
                                                                }
                                                                if (keep > 0)
                                                                {
                                                                    recvTimer.timeout(keep, timerKeepHandler);
                                                                }
                                                            }
                                                        });
                                                        break;
                                                    case NamedType.Ptr:
                                                        if (!isTcp)
                                                        {
                                                            generator.select_chans.stop_all();
                                                        }
                                                        await generator.csp_wait((NamedPtrCsp)tempNode.Value.csp, async delegate (RecvPtrParam param)
                                                        {
                                                            int count = param.count;
                                                            if (count > len2 - position)
                                                            {
                                                                count = len2 - position;
                                                            }
                                                            if (count <= 0)
                                                            {
                                                                recvTimer.restart();
                                                                return 0;
                                                            }
                                                            try
                                                            {
                                                                recvBin = true;
                                                                recvTimer.cancel();
                                                                if (param.timed >= 0)
                                                                {
                                                                    recvTimer.timeout(param.timed, timerRecvHandler);
                                                                }
                                                                generator.lock_stop();
                                                                socket_result result = await ((socket_tcp)_socket).read(param.pointer, param.offset, count);
                                                                generator.unlock_stop();
                                                                if (!result)
                                                                {
                                                                    position = -1;
                                                                    return -1;
                                                                }
                                                                position += result.size;
                                                                return result.size;
                                                            }
                                                            finally
                                                            {
                                                                recvBin = false;
                                                                if (param.timed >= 0)
                                                                {
                                                                    recvTimer.cancel();
                                                                }
                                                                if (keep > 0)
                                                                {
                                                                    recvTimer.timeout(keep, timerKeepHandler);
                                                                }
                                                            }
                                                        });
                                                        break;
                                                }
                                                namedMap.Remove(tempNode);
                                                if (-1 == position)
                                                {
                                                    goto socketClosed;
                                                }
                                            }
                                        }
                                        break;
                                    case DataType.BinCancel:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        {
                                            var tempNode = namedMap.FindFirst(id);
                                            if (null == tempNode)
                                            {
                                                do
                                                {
                                                    chan_recv_wrap<NamedRecvParam> namedCsp = await _namedRecvChan.receive(namedLost);
                                                    tempNode = namedMap.Insert(namedCsp.msg.name._id, namedCsp.msg);
                                                } while (tempNode.Key != id);
                                            }
                                            switch (tempNode.Value.csp.Type)
                                            {
                                                case NamedType.Byte:
                                                    await generator.csp_wait((NamedByteCsp)tempNode.Value.csp, (RecvByteParam _) => new ValueTask<int>(-2));
                                                    break;
                                                case NamedType.Ptr:
                                                    if (!isTcp)
                                                    {
                                                        generator.select_chans.stop_all();
                                                    }
                                                    await generator.csp_wait((NamedPtrCsp)tempNode.Value.csp, (RecvPtrParam _) => new ValueTask<int>(-2));
                                                    break;
                                            }
                                            namedMap.Remove(tempNode);
                                        }
                                        break;
                                    case DataType.Close:
                                        if (0 != len1 || 0 != len2)
                                        {
                                            goto dataHeadError;
                                        }
                                        setCode(ExitCode.RemoteClose);
                                        return;
                                    default:
                                        goto dataHeadError;
                                }
                            }
dataHeadError:
                            setCode(ExitCode.DataHeadError);
                            return;
socketClosed:
                            setCode(ExitCode.SocketClosed);
                            return;
                        }
                        finally
                        {
                            generator.lock_stop();
                            recvTimer.cancel();
                            _action.stop();
                            _namedRecvChan.close();
                            _recvByteChan.close();
                            _recvPtrChan.close();
                            if (namedLost.has)
                            {
                                namedLost.msg.csp.Close();
                                namedLost.clear();
                            }
                            while (true)
                            {
                                var wrap = await _namedRecvChan.receive();
                                if (wrap.state != chan_state.ok)
                                {
                                    break;
                                }
                                wrap.msg.csp.Close();
                            }
                            foreach (var item in namedMap)
                            {
                                item.value2.csp.Close();
                            }
                            generator.unlock_stop();
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        byte[] sendHead = new byte[17];
                        byte[] sendBuff1 = new byte[sendHead.Length + 1024 * 1024];
                        byte[] sendBuff2 = new byte[sendHead.Length + 1024 * 1024];
                        wait_group sendBuffWg = new wait_group();
                        chan_lost_msg<SendBuffParam> sendBuffLost = new chan_lost_msg<SendBuffParam>();
                        chan_lost_msg<SendRequestParam> sendRequestLost = new chan_lost_msg<SendRequestParam>();
                        chan<SendBuffParam> sendBuffChan = chan<SendBuffParam>.make(1);
                        generator.children serializerChild = new generator.children();
                        serializerChild.go(async delegate ()
                        {
                            BinaryFormatter serializer = new BinaryFormatter();
                            try
                            {
                                await generator.select().case_receive(sendReplyChan, async delegate (SendReplyParam param)
                                {
                                    int len1 = 0, len2 = 0;
                                    await generator.send_task(delegate ()
                                    {
                                        try
                                        {
                                            MemoryStream sendStream = new MemoryStream(sendBuff1, sendHead.Length, sendBuff1.Length - sendHead.Length);
                                            serializer.Serialize(sendStream, param.reply);
                                            len1 = (int)sendStream.Position;
                                            if (null != param.result)
                                            {
                                                try
                                                {
                                                    if (param.result is ParamTuple)
                                                    {
                                                        param.result = ((ParamTuple)param.result).Objects;
                                                    }
                                                    serializer.Serialize(sendStream, param.result);
                                                    len2 = (int)sendStream.Position - len1;
                                                }
                                                catch (Exception)
                                                {
                                                    sendStream.Position = 0;
                                                    serializer.Serialize(sendStream, new Reply { state = ReplyState.RemoteSerializeError });
                                                    len1 = (int)sendStream.Position;
                                                }
                                            }
                                        }
                                        catch (Exception)
                                        {
                                            setCode(ExitCode.ReplySerializeError);
                                            throw;
                                        }
                                    });
                                    WriteHead(sendBuff1, param.id, len1, len2, DataType.Reply);
                                    await sendBuffWg.wait();
                                    sendBuffWg.add();
                                    Swap(ref sendBuff1, ref sendBuff2);
                                    sendBuffChan.post(new SendBuffParam { count = sendHead.Length + len1 + len2 });
                                }).case_receive(sendRequestChan, async delegate (SendRequestParam param)
                                {
                                    int len1 = 0, len2 = 0;
                                    sendRequestLost.set(param);
                                    if (!await generator.send_task(delegate ()
                                    {
                                        try
                                        {
                                            MemoryStream sendStream = new MemoryStream(sendBuff1, sendHead.Length, sendBuff1.Length - sendHead.Length);
                                            serializer.Serialize(sendStream, param.request);
                                            len1 = (int)sendStream.Position;
                                            if (null != param.args)
                                            {
                                                try
                                                {
                                                    for (int i = 0; i < param.args.Length; i++)
                                                    {
                                                        if (param.args[i] is ParamTuple)
                                                        {
                                                            param.args[i] = ((ParamTuple)param.args[i]).Objects;
                                                        }
                                                    }
                                                    serializer.Serialize(sendStream, param.args);
                                                    len2 = (int)sendStream.Position - len1;
                                                }
                                                catch (Exception)
                                                {
                                                    recvReplyChan.post(new RecvReplyParam { id = param.id, state = ReplyState.Success, reply = new Reply { state = ReplyState.LocalSerializeError } });
                                                    return false;
                                                }
                                            }
                                            return true;
                                        }
                                        catch (Exception)
                                        {
                                            setCode(ExitCode.RequestSerializeError);
                                            throw;
                                        }
                                    }))
                                    {
                                        param.overSend?.Close();
                                        sendRequestLost.clear();
                                        return;
                                    }
                                    WriteHead(sendBuff1, param.id, len1, len2, DataType.Request);
                                    await sendBuffWg.wait();
                                    sendBuffWg.add();
                                    Swap(ref sendBuff1, ref sendBuff2);
                                    sendRequestLost.clear();
                                    sendBuffChan.post(new SendBuffParam { count = sendHead.Length + len1 + len2, overSend = param.overSend });
                                }, lostMsg: sendRequestLost).loop();
                            }
                            catch (generator.stop_exception) { throw; }
                            catch (Exception) { }
                            finally
                            {
                                generator.lock_stop();
                                _action.stop();
                                if (sendRequestLost.has)
                                {
                                    sendRequestLost.msg.overSend?.Close();
                                    sendRequestLost.clear();
                                }
                                generator.unlock_stop();
                            }
                        });
                        try
                        {
                            chan<void_type> keepChan = chan<void_type>.make(1);
                            Action timerKeepHandler = keepChan.wrap_try_default();
                            Action timerSendHandler = delegate ()
                            {
                                setCode(ExitCode.SendBinOvertime);
                                _action.stop();
                            };
                            if (keep > 0)
                            {
                                sendTimer.interval(keep / 2, timerKeepHandler);
                            }
                            await generator.select().case_receive(_remoteCmdChan, async delegate (DataType cmd)
                            {
                                WriteHead(sendHead, 0L, 0, 0, cmd);
                                switch (cmd)
                                {
                                    case DataType.NoKeep:
                                        keep = -1;
                                        sendTimer.cancel();
                                        if (!recvBin)
                                        {
                                            recvTimer.cancel();
                                        }
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                        }
                                        break;
                                    case DataType.Close:
                                        if (!await _socket.write(sendHead))
                                        {
                                            generator.select_chans.stop_all();
                                        }
                                        setCode(ExitCode.LocalClose);
                                        _remoteCmdChan.close();
                                        await generator.hold();
                                        break;
                                }
                            }).case_receive(_cancelRpcChan, async delegate (long id)
                            {
                                WriteHead(sendHead, id, 0, 0, DataType.RequestCancel);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                            }).case_receive(sendBuffChan, async delegate (SendBuffParam param)
                            {
                                param.overSend?.wg.done();
                                if (!await _socket.write(new ArraySegment<byte>(sendBuff2, 0, param.count)))
                                {
                                    generator.select_chans.stop_all();
                                }
                                sendBuffWg.done();
                            }, lostMsg: sendBuffLost).case_receive(_cancelSendChan, async delegate (SendName name)
                            {
                                if (name._done)
                                {
                                    return;
                                }
                                name._done = true;
                                WriteHead(sendHead, name._id, 0, 0, DataType.BinCancel);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                            }).case_receive(_sendByteChan, async delegate (SendByteParam param)
                            {
                                if (param.name._done)
                                {
                                    return;
                                }
                                if (param.data.Count <= 0)
                                {
                                    return;
                                }
                                WriteHead(sendHead, param.name._id, param.index, param.data.Count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                                try
                                {
                                    sendBin = true;
                                    sendTimer.cancel();
                                    if (param.timed >= 0)
                                    {
                                        sendTimer.timeout(param.timed, timerSendHandler);
                                    }
                                    generator.lock_stop();
                                    socket_result result = await _socket.write(param.data);
                                    generator.unlock_stop();
                                    if (!result)
                                    {
                                        generator.select_chans.stop_all();
                                    }
                                }
                                finally
                                {
                                    sendBin = false;
                                    if (param.timed >= 0)
                                    {
                                        sendTimer.cancel();
                                    }
                                    if (keep > 0)
                                    {
                                        sendTimer.interval(keep / 2, timerKeepHandler);
                                    }
                                }
                            }).case_receive(_sendPtrChan, async delegate (SendPtrParam param)
                            {
                                if (param.name._done)
                                {
                                    return;
                                }
                                if (param.count <= 0)
                                {
                                    return;
                                }
                                if (!isTcp)
                                {
                                    generator.select_chans.stop_all();
                                }
                                WriteHead(sendHead, param.name._id, param.index, param.count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                                try
                                {
                                    sendBin = true;
                                    sendTimer.cancel();
                                    if (param.timed >= 0)
                                    {
                                        sendTimer.timeout(param.timed, timerSendHandler);
                                    }
                                    generator.lock_stop();
                                    socket_result result = await ((socket_tcp)_socket).write(param.pointer, param.offset, param.count);
                                    generator.unlock_stop();
                                    if (!result)
                                    {
                                        generator.select_chans.stop_all();
                                    }
                                }
                                finally
                                {
                                    sendBin = false;
                                    if (param.timed >= 0)
                                    {
                                        sendTimer.cancel();
                                    }
                                    if (keep > 0)
                                    {
                                        sendTimer.interval(keep / 2, timerKeepHandler);
                                    }
                                }
                            }).case_receive(_sendFileChan, async delegate (SendFileParam param)
                            {
                                if (param.name._done)
                                {
                                    return;
                                }
                                if (param.count <= 0)
                                {
                                    return;
                                }
                                if (!isTcp)
                                {
                                    generator.select_chans.stop_all();
                                }
                                WriteHead(sendHead, param.name._id, param.index, param.count, DataType.Bin);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                                try
                                {
                                    sendBin = true;
                                    sendTimer.cancel();
                                    if (param.timed >= 0)
                                    {
                                        sendTimer.timeout(param.timed, timerSendHandler);
                                    }
                                    generator.lock_stop();
                                    socket_result result = await ((socket_tcp)_socket).send_file(param.file, param.offset, param.count);
                                    generator.unlock_stop();
                                    if (!result)
                                    {
                                        generator.select_chans.stop_all();
                                    }
                                }
                                finally
                                {
                                    sendBin = false;
                                    if (param.timed >= 0)
                                    {
                                        sendTimer.cancel();
                                    }
                                    if (keep > 0)
                                    {
                                        sendTimer.interval(keep / 2, timerKeepHandler);
                                    }
                                }
                            }).case_receive(keepChan, async delegate ()
                            {
                                WriteHead(sendHead, 0L, 0, 0, DataType.Keep);
                                if (!await _socket.write(sendHead))
                                {
                                    generator.select_chans.stop_all();
                                }
                            }).loop();
                            setCode(ExitCode.SocketClosed);
                        }
                        finally
                        {
                            generator.lock_stop();
                            await serializerChild.stop();
                            sendTimer.cancel();
                            _action.stop();
                            _sendPtrChan.close();
                            _sendByteChan.close();
                            _sendFileChan.close();
                            _cancelRpcChan.close();
                            _cancelSendChan.close();
                            _remoteCmdChan.close();
                            sendBuffChan.close();
                            if (sendBuffLost.has)
                            {
                                sendBuffLost.msg.overSend?.Close();
                                sendBuffLost.clear();
                            }
                            while (true)
                            {
                                var wrap = await sendBuffChan.receive();
                                if (wrap.state != chan_state.ok)
                                {
                                    break;
                                }
                                wrap.msg.overSend?.Close();
                            }
                            generator.unlock_stop();
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        mt19937 mt = new mt19937();
                        shared_strand selfStrand = generator.self_strand();
                        generator.children callChild = new generator.children();
                        Dictionary<long, RpcCancel> rpcCancelDict = new Dictionary<long, RpcCancel>();
                        while (true)
                        {
                            RecvRequestParam request = await recvRequestChan.receive();
                            OverRecv[] recvs = null;
                            if (null != request.request.sends)
                            {
                                recvs = new OverRecv[request.request.sends.Length];
                                for (int i = 0; i < request.request.sends.Length; i++)
                                {
                                    recvs[i] = new OverRecv(request.request.sends[i]);
                                }
                            }
                            if (request.cancel)
                            {
                                if (rpcCancelDict.TryGetValue(request.id, out RpcCancel rpcCancel))
                                {
                                    rpcCancelDict.Remove(request.id);
                                    rpcCancel.wg.done();
                                }
                                if (null != recvs)
                                {
                                    callChild.free_go(selfStrand, () => DiscardRecv(recvs));
                                }
                                continue;
                            }
                            tuple<Func<async_result_wrap<object, ReplyState>, object[], Task>, shared_strand> handler;
                            if (null == request.request.name || null == request.args || !_methods.Get(request.request.name, out handler))
                            {
                                sendReplyChan.post(new SendReplyParam { id = request.id, reply = new Reply { state = ReplyState.NotFound } });
                                if (null != recvs)
                                {
                                    callChild.free_go(selfStrand, () => DiscardRecv(recvs));
                                }
                            }
                            else
                            {
                                RpcCancel rpcCancel = new RpcCancel { wg = new wait_group(1) };
                                rpcCancelDict.Add(request.id, rpcCancel);
                                callChild.free_go(handler.value2 ?? _strands[1 == _strands.Length ? 0 : (1 + (int)((_strands.Length - 1) * mt.NextDouble()))], async delegate ()
                                {
                                    bool cancel = false;
                                    object result = default;
                                    Reply reply = new Reply();
                                    try
                                    {
                                        _session.value = this;
                                        _rpcCancel.value = rpcCancel;
                                        _recvList.value = new RecvList { recvs = recvs };
                                        async_result_wrap<object, ReplyState> resultWrap = new async_result_wrap<object, ReplyState> { value2 = ReplyState.Success };
                                        await handler.value1(resultWrap, request.args);
                                        reply.state = resultWrap.value2;
                                        result = resultWrap.value1;
                                    }
                                    catch (generator.stop_exception)
                                    {
                                        reply.state = ReplyState.Stopped;
                                        throw;
                                    }
                                    catch (CancelException)
                                    {
                                        reply.state = ReplyState.RemoteCancel;
                                        cancel = true;
                                    }
                                    catch (CastArgsException)
                                    {
                                        reply.state = ReplyState.ArgsTypeError;
                                    }
                                    catch (Exception ec)
                                    {
                                        reply.state = ReplyState.Exception;
                                        if (null != ec.InnerException)
                                        {
                                            Exception inner = ec.InnerException;
                                            reply.message = $"{inner.Message}\r\n{ec.Message}\r\n{inner.Source}\r\n{ec.Source}\r\n{inner.StackTrace}\r\n{ec.StackTrace}";
                                        }
                                        else
                                        {
                                            reply.message = $"{ec.Message}\r\n{ec.Source}\r\n{ec.StackTrace}";
                                        }
                                    }
                                    finally
                                    {
                                        generator.lock_stop();
                                        ClearCallback();
                                        if (!cancel && request.request.reply)
                                        {
                                            sendReplyChan.post(new SendReplyParam { id = request.id, result = result, reply = reply });
                                        }
                                        if (selfStrand.running_in_this_thread())
                                        {
                                            if (rpcCancelDict.Remove(request.id) && cancel && request.request.reply)
                                            {
                                                sendReplyChan.post(new SendReplyParam { id = request.id, result = result, reply = reply });
                                            }
                                        }
                                        else
                                        {
                                            selfStrand.post(delegate ()
                                            {
                                                if (rpcCancelDict.Remove(request.id) && cancel && request.request.reply)
                                                {
                                                    sendReplyChan.post(new SendReplyParam { id = request.id, result = result, reply = reply });
                                                }
                                            });
                                        }
                                        await generator.children.stop(generator.all_children());
                                        if (null != recvs)
                                        {
                                            await DiscardRecv(recvs);
                                        }
                                        generator.unlock_stop();
                                    }
                                });
                            }
                        }
                    });
                    ioChild.go(async delegate ()
                    {
                        while (true)
                        {
                            RecvReplyParam reply = await recvReplyChan.receive();
                            if (replyMap.TryGetValue(reply.id, out var replyPack))
                            {
                                replyMap.Remove(reply.id);
                                replyPack.timer?.cancel();
                                if (reply.state == ReplyState.Success)
                                {
                                    replyPack.result.complete(new Result { state = reply.reply.state, result = reply.result, message = reply.reply.message });
                                }
                                else
                                {
                                    replyPack.result.complete(new Result { state = reply.state });
                                }
                            }
                        }
                    });
                    while (true)
                    {
                        var rpc = await _rpcChan.wait(rpcLost);
                        if (rpc.state != chan_state.ok)
                        {
                            break;
                        }
                        long id = rpc.msg.id;
                        if (rpc.msg.timed > 0)
                        {
                            rpc.msg.request.reply = true;
                            async_timer timer = new async_timer();
                            replyMap.Add(id, new ReplyMapValue { timer = timer, result = rpc.result });
                            timer.timeout(rpc.msg.timed, () => recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.Overtime }));
                        }
                        else if (rpc.msg.timed < 0)
                        {
                            rpc.msg.request.reply = true;
                            replyMap.Add(id, new ReplyMapValue { result = rpc.result });
                        }
                        else
                        {
                            rpc.msg.request.reply = false;
                            rpc.complete(new Result { state = ReplyState.Success });
                        }
                        if (null != rpc.msg.overCancel.wg)
                        {
                            rpc.msg.overCancel.wg.async_wait(() => recvReplyChan.post(new RecvReplyParam { id = id, state = ReplyState.LocalCancel }));
                        }
                        sendRequestChan.post(new SendRequestParam { id = id, args = rpc.msg.args, request = rpc.msg.request, overSend = rpc.msg.overSend });
                    }
                    setCode(ExitCode.SessionClose);
                }
                catch (generator.stop_exception)
                {
                    setCode(ExitCode.SessionClose);
                    throw;
                }
                finally
                {
                    generator.lock_stop();
                    _socket.close();
                    await ioChild.stop();
                    _rpcChan.close();
                    sendRequestChan.close();
                    if (rpcLost.has)
                    {
                        rpcLost.msg.msg.overSend?.Close();
                        rpcLost.msg.fail();
                        rpcLost.clear();
                    }
                    foreach (var item in replyMap)
                    {
                        item.Value.timer?.cancel();
                        item.Value.result.fail();
                    }
                    while (true)
                    {
                        var wrap = await _rpcChan.wait();
                        if (wrap.state != chan_state.ok)
                        {
                            break;
                        }
                        wrap.msg.overSend?.Close();
                        wrap.fail();
                    }
                    while (true)
                    {
                        var wrap = await sendRequestChan.receive();
                        if (wrap.state != chan_state.ok)
                        {
                            break;
                        }
                        wrap.msg.overSend?.Close();
                    }
                    generator.unlock_stop();
                }
            }
        }
    }
}
